/**********************************************************************
 * file:  sr_router.c 
 * date:  Mon Feb 18 12:50:42 PST 2002  
 * Contact: casado@stanford.edu 
 *
 * Description:
 * 
 * This file contains all the functions that interact directly
 * with the routing table, as well as the main entry method
 * for routing.
 *
 **********************************************************************/

#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>

#include "sr_if.h"
#include "sr_rt.h"
#include "sr_router.h"
#include "sr_protocol.h"

#include "sr_arp.h"
#include "sr_ip.h"

extern pthread_mutex_t arp_q_mutex;

/*--------------------------------------------------------------------- 
 * Method: sr_init(void)
 * Scope:  Global
 *
 * Initialize the routing subsystem
 * 
 *---------------------------------------------------------------------*/

void sr_init(struct sr_instance* sr) 
{
    /* REQUIRES */
    assert(sr);

    pthread_t arp_check_thread;
    pthread_t arp_check_q_thread;

    /* initialize ARP table to be empty */
    sr->arp_table = 0;
    sr->arp_queue = 0;

    /* initialize arp_q_mutex */
    pthread_mutexattr_t attr;
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&arp_q_mutex, &attr);
    pthread_mutexattr_destroy(&attr);

    pthread_create(&arp_check_thread, NULL, sr_check_arp_entries, (void*)sr);
    pthread_create(&arp_check_q_thread, NULL, sr_check_arp_queue, (void*)sr);

} /* -- sr_init -- */



/*---------------------------------------------------------------------
 * Method: sr_handlepacket(uint8_t* p,char* interface)
 * Scope:  Global
 *
 * This method is called each time the router receives a packet on the
 * interface.  The packet buffer, the packet length and the receiving
 * interface are passed in as parameters. The packet is complete with
 * ethernet headers.
 *
 * Note: Both the packet buffer and the character's memory are handled
 * by sr_vns_comm.c that means do NOT delete either.  Make a copy of the
 * packet instead if you intend to keep it around beyond the scope of
 * the method call.
 *
 *---------------------------------------------------------------------*/

void sr_handlepacket(struct sr_instance* sr, 
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
    /* REQUIRES */
    assert(sr);
    assert(packet);
    assert(interface);

    printf("*** -> Received packet of length %d \n",len);

    struct sr_ethernet_hdr* e_hdr = (struct sr_ethernet_hdr *)packet;
    uint16_t p_type = ntohs(e_hdr->ether_type);

    switch(p_type) 
    {
        case ETHERTYPE_IP:
            printf("IP packet received...\n");
            sr_handle_ip(sr, packet,len, interface);
            break;
        case ETHERTYPE_ARP:
            printf("ARP packet received...\n");
            sr_handle_arp(sr, packet, len, interface);
            break;
        default:
            printf("Unknown packet received... Packet type 0x%40x\n", p_type);
    }
}/* end sr_ForwardPacket */



